<?php  


class News_UI_Queue
{ 
    var $Path; 
    var $Param; 
    var $Request; 
    var $Controller;
    var $Items;
    var $Busy; 
    function News_UI_Queue($controller, $id = NULL)
    {
        $this->Controller = $controller;
        $this->Request    = $controller->Settings['request'];
        $this->Path       = 'data/queue'; 
        if (!is_dir($this->Path)) mkdir ($this->Path);
        if ($id) $this->Recall ($id);
        $this->Load();
    } 
     
    
    function ShowList()
    {
        $arr = $this->Controller->OpenDir ($this->Path . '/');
        $htm = array ('<table width="100%" cellspacing="0">');
        $out = array('toolbar'=>$this->Controller->Factory->TabBar('Queue'));
        for ($x=0;$x<sizeof($arr);$x++)
        { 
            parse_str($this->Controller->Read($arr[$x]['path']));
            $this->Recall ($Id);
            $subj  = base64_decode ($Subject);
            
            $kill  = "/ui/commandhandler/request/kill/group/{$Group}/id/{$Id}";
            $kill  = $this->Controller->Factory->Button ($kill, 'Delete', 'i.p.delete.gif'); 
		    $href  = "<a href='/ui/commandhandler/request/group/group/{$Group}'>{$Group}</a>";
            $stat  = $this->IsRunning() ? $this->Parseff () : 'Waiting...';
            $htm[] = '<tr><td class=bullet>';
            $htm[] = "<img src='/{$Picture}' width='120'/>";
            $htm[] = '</td>';
            $htm[] = "<td class=bullet width='100%'>{$kill}{$subj}<br/>{$href}<div id='{$Id}'>{$stat}</div></td>";
            $htm[] = '</tr>';
        }
        $htm[] = '</table>';
        $out['main'] = implode ('', $htm);
		echo $this->Controller->Structure ($out); 
    } 
     
    
    function GetStatus()
    {
        return sprintf('%s %s', strlen($this->Param['PID'])==0?'queued for':'', $this->Param['Type']==TYPE_RAR?'downloading':'encoding');
    } 
     
    
    function Load()
    {
        $this->Busy  = false;
        $this->Items = array();
        $arr = $this->Controller->OpenDir ($this->Path . '/');
        for ($x=0;$x<sizeof($arr);$x++)
        {
            $PID = '';
            parse_str($this->Controller->Read($arr[$x]['path']));
            $this->Items[] = $Id;
            if (strlen($PID) > 0)
            {
                $this->Busy = true;
            }
        }
    } 
     
     
    
    function Recall($id)
    {
        $arr = explode ('-', $id);
        $key = $arr[0];
        
        $b64 = base64_encode($key);
        $loc = "{$this->Path}/{$b64}.queue";
        if (file_exists($loc))
        {
            parse_str($this->Controller->Read($loc));
            $this->Param = array (
		        'Id'       => $Id, //array_pop($tmp),       
		        'Name'     => $Name, //$picture,       
		        'Path'     => $Path, //$videofile,       
		        'Seconds'  => $Seconds, //$videofile,       
		        'Duration' => $Duration, //$dur,       
		        'Picture'  => $Picture, //$dur,       
		        'Group'    => $Group, //$dur,         
		        'Index'    => $Index, //$dur,         
		        'Type'     => $Type, //$dur,         
		        'Subject'  => $Subject, //$dur,       
		        'PID'      => $PID); //$id );        
            return true;
        }
        return false;
    }
    
    function GetDuration ($videofile)
    {
        ob_start();
        passthru("ffmpeg -i \"{$videofile}\" 2>&1");
        $source = ob_get_contents();
        ob_end_clean();

        if (preg_match('/Duration: (.*?),/', $source, $matches))
            $dur = $matches[1];    
        return $dur;
    }
    
    function ReadRar ($id, $index, $group, $subject)
    {
        $arr  = explode ('-', $id);
        $key  = $arr[0];  
        
        $this->Param = array (  
		        'Id'       => $key,
		        'Index'    => $index, 
		        'Picture'  => ICON_RAR,     
		        'Type'     => TYPE_RAR,     
                'Group'    => $group,
                'Subject'  => base64_encode($subject) );  
    }
    
    function Read ($videofile, $id, $group, $subject)
    {
        $arr  = explode ('-', $id);
        $key  = $arr[0];  
        $dur  = $this->GetDuration($videofile);  
        $secs = $this->ToSeconds($dur);  
        $ss   = $secs > 30 ? 30 : ($secs / 2); 
        $pic  = "{$videofile}-temp.jpg"; 
        $tmp  = explode ('/', $videofile);
        $name = array_pop($tmp);    
        
        
        $this->VideoFrame($videofile, $ss, $pic);
        
        $this->Param = array (  
		        'Id'       => $key, 
		        'Name'     => $name,       
		        'Path'     => $videofile,       
		        'Duration' => $dur,       
		        'Seconds'  => $secs, 
		        'Picture'  => $pic,     
		        'Type'     => TYPE_MOVIE,     
                'Group'    => $group,
                'Subject'  => base64_encode($subject) ); 
        
        $this->Fancy ("File: " . $this->Param['Name']); 
        $this->Fancy ("Duration: " . $this->Param['Duration'], 220);   
    }
    
    function Start ()
    { 
        $pid = NULL;
        if (!$this->Busy)
        { 
            switch ($this->Param['Type'])
            {
                case TYPE_RAR:
                    $pid = $this->AsyncDownload();
                    break;
                case TYPE_MOVIE:
                    $pid = $this->VideoEncode ($this->Param['Path']);
                    break;
            }
        }
        $this->Add ($pid);
    }
    
    function ToSeconds($dur)
    {
        $tmp  = split(':', $dur);
        return $tmp[0] * 3600 + $tmp[1] * 60 + $tmp[2];
    }
    
    function Add($pid = NULL)
    {
        $id  = $this->Param['Id'];
        $b64 = base64_encode($id);
        $loc = "{$this->Path}/{$b64}.queue";
        if ($pid)
        {
            $this->Param['PID']   = $pid;
        } 
        $ret = array();
        while (list ($name, $value) = each ($this->Param))
        {
            $ret[] = "{$name}={$value}";
        } 
        $this->Controller->Save ($loc, implode('&', $ret));
    } 

    function CreateIndex($dir = NULL, $id = NULL, $subj = NULL, $file = NULL, $dur = NULL, $pic = NULL)
    {
        $folder   = $dir  ? $dir  : sprintf('data/tube/%s', $this->Param['Group']);
        $subject  = $subj ? $subj : base64_decode($this->Param['Subject']);  
        $key      = $id   ? $id   : $this->Param['Id'];  
        $filename = $file ? $file : $this->Param['Path'];  
        $duration = $dur  ? $dur  : $this->Param['Duration'];  
        $picture  = $pic  ? $pic  : $this->Param['Picture'];
        $idxpath  = "{$folder}/{$key}.idx";
        $xml      = "<?xml version='1.0' encoding='ISO-8859-1'?>\n" . 
                    "<index>\n" . 
                    "  <id><![CDATA[{$key}]]></id>\n" .  
                    "  <subject><![CDATA[{$subject}]]></subject>\n" . 
                    "  <duration><![CDATA[{$duration}]]></duration>\n" . 
                    "  <picture><![CDATA[{$picture}]]></picture>\n";
        
        if (is_array($file))
        {
            $xml .= '<files>';
		    foreach ($file as $f)
		    {
		        if (!($f=='.'||$f=='..'))
		        {
		            $xml .=  "  <name><![CDATA[{$f}]]></name>\n";
		        }
		    }
            $xml .= '</files>';
        }
        else
        {
            $xml .=  "  <name><![CDATA[{$filename}]]></name>\n";
        }
        $xml     .= "</index>";    
        $this->Controller->Save ($idxpath, $xml);
    } 

    
    function Dispose($id)
    {
        $this->Recall($id);
        if ($this->IsRunning())
        {
            $command = "kill -9 " . $this->Param['PID'];
            echo $command;
            passthru ($command);
        }
        $this->Remove(false);
    } 
    
    function Remove($save = true)
    { 
        $id     = $this->Controller->Settings['id']; 
        $b64    = base64_encode($id);
        $loc    = "{$this->Path}/{$b64}.queue"; 
        
        unlink ($loc);
        unlink ($this->StdOutName());
        
        if ($this->Param['Type'] == TYPE_MOVIE)
        {
            $secs = $this->ToSeconds($this->Param['Duration']);
	        unlink ($this->Param['Picture']);
	        unlink ($this->Param['Path']);
	        
	        $this->Param['Path'] .= '.m4v';
	        if ($save && file_exists($this->Param['Path']))
	        { 
		        $this->Param['Picture']  = $this->VideoFrame ($this->Param['Path'], $secs > 30 ? 30 : ($secs / 2));  
		        $this->CreateIndex();
		        
		        $this->Fancy ("File: " . $this->Param['Name']); 
		        $this->Fancy ("Duration: " . $this->Param['Duration'], 220);  
	        }
	        else if (file_exists($this->Param['Path']))
	        { 
	            unlink ($this->Param['Path']);
	        }
        }
        $this->Load();
        return 'OK';
    }
    
    function VideoFrame($path, $secs = NULL, $name = NULL)
    {
        $output = $name ? $name : "{$path}.jpeg";
        $ss     = $secs ? $secs : 15;
        $c=("ffmpeg -i \"{$path}\" -vcodec mjpeg -vframes 1 -ss {$ss} -an -f rawvideo -s 320x240 \"{$output}\"");
        passthru($c);
        return $output;
    }


    function StdOutName()
    {
        return '/var/www/html/' . $this->Param['Id'] . '.out';
//        return $this->Param['Type'] == TYPE_MOVIE ? '/var/www/html/command.out' : '/var/www/html/rar.out';
    }


    function Run($Command, $Priority = 0)
    {
        $out = $this->StdOutName();
        
        if (file_exists($out)) unlink ($out); 
        if($Priority)
            $PID = shell_exec("nohup nice -n $Priority $Command > /dev/null & echo $!");
        else
            $PID = shell_exec("nohup $Command 1> $out & echo $!");
        return($PID);
    }
    
    function AsyncDownload()
    {
        $group = $this->Param['Group'];
        $index = $this->Param['Index'];
        $command = "php index.php dl {$group} {$index}";
        echo "{$command}\n";
        $pid = $this->Run($command);
        return $pid;
    }
    
    function VideoEncode ($path)
    { 
        $output = $path . '.m4v'; 
        $command = "ffmpeg -i \"{$path}\" -f mp4 -vcodec libx264 -vpre default " .
                   "-bufsize 1835k -acodec libfaac " .
                   "-b 400k \"{$output}\""; 
        $pid = $this->Run($command);
        return $pid;
    }
	
	function Readff()
	{
        $fn = $this->StdOutName();
        $d  = $this->Param['Type'] == TYPE_RAR ? "\n" : "\r";
//	    $fn = 'command.out';
//	    $fn = 'data/' . $this->Param['Name'] . '.out';
	    $fp=fopen($fn, 'r');
	    $fr=fread($fp,filesize($fn));
	    fclose($fp); 
	    
	    $tmp = explode ($d, $fr);
	    $line = '';
	    if (sizeof($tmp)>0)
	    {
	        $x=0;
	        while (strlen($line)==0 && ++$x < 100)
	            $line = array_pop($tmp); 
	    }
//	    echo $line;
	    return $line; 
	}

    function IsRunning()
    {
        if (isset($this->Param['PID']))
        {
	        $PID = $this->Param['PID'];
	        exec("ps $PID", $ProcessState);
	        return(count($ProcessState) >= 2);
        }
        return false;
    }
    
    function Fancy ($message, $y = 206)
    { 
        $im      = imagecreatefromjpeg($this->Param['Picture']);
        $black   = imagecolorallocate ($im, 0, 0, 0);
        $blue    = imagecolorallocate ($im, 99, 99, 255);
        $white   = imagecolorallocate ($im, 255, 255, 255);
        $font    = 'verdana.ttf';
	    imagettftext($im,  10, 0, 10, $y, $black , $font, $message); 
	    imagettftext($im,  10, 0, 9, $y - 1, $white , $font, $message); 
	    imagejpeg ($im, $this->Param['Picture'], 75);
	    imagedestroy($im);
        
    }
    
    function Parseff()
    {
        $line = $this->Readff();
        if ($this->Param['Type'] == TYPE_RAR)
        {
            return $line;
        }
        if (preg_match('/time=(.*)\s+bit/i', $line, $matches))
        {
            $time    = $matches[1];     
            $secs    = $this->ToSeconds($this->Param['Duration']); 
            $percent = $time / $secs;
            $num     = ceil ($percent * 100) . '%';
            $pattern = 'Encoding "%s" %s of %s...';
            $msg = sprintf($pattern, $this->Param['Name'], $num, $this->Param['Duration']);  
            return $msg; 
        }
		
        return $line;
    }
    
    function Display()
    {
        if ($this->Request=='list')
        {
            $this->ShowList();
            return;
        }
        $id = $this->Controller->Settings['id'];
        $ok = $this->Recall ($id);
        if (!$ok) 
        {
            echo "{$id} not found!";  
            return;
        }
        else if (strlen($this->Param['PID']) == 0)
        { 
            if ($this->Busy)
            {
                echo date('h:i:s') . ': ' .  base64_decode($this->Param['Subject']) . ' is ' . $this->GetStatus(); //" waiting...";
                return;
            }
            $notify = "notify/{$id}.start";
            if (!file_exists($notify))
            {
                echo "Starting queue for {$id}...";
                $this->Controller->Save ($notify, $this->Param['Subject']);
				return;
            }
            echo "Waiting for queue start {$id}...";
            return;
        }
        else if (!$this->IsRunning())
        {
            echo $this->Remove(); 
            return;
        }
        $line = $this->Parseff();
   
        if ($line)
        { 
            echo date('h:i:s') . ': ' . $line; 
            return;
        }
        echo $this->Param['PID'] . ',' . $this->Param['Id'];
    }
}